/**
 * @addtogroup FXCRT
 * @{
 */

/**
 * @file
 * @brief FXCRT debug & test
 */

#ifndef _FXM_OPENSOURCE_

#ifndef _FXCRT_DEBUG_
#define _FXCRT_DEBUG_

#ifndef _FX_SYSTEM_H_
	#include "fx_system.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

//*****************************************************************************
//* Simple debugging functions
//*****************************************************************************
/**
 * @brief	External debugging functions. Caller should implement the two functions in application.
 */
extern void FX_OUTPUT_LOG_FUNC(const char*, ...);
extern int FX_GET_TICK_FUNC();

#ifdef _FOXIT_DEBUG_
	#ifndef FOXIT_DEBUG1
		#define FOXIT_DEBUG1(msg) FX_OUTPUT_LOG_FUNC(msg)
	#endif
	#ifndef FOXIT_DEBUG2
		#define FOXIT_DEBUG2(msg,param1) FX_OUTPUT_LOG_FUNC(msg,param1)
	#endif
	#ifndef FOXIT_DEBUG3
		#define FOXIT_DEBUG3(msg,param1,param2) FX_OUTPUT_LOG_FUNC(msg,param1,param2)
	#endif
	#ifndef FOXIT_DEBUG4
		#define FOXIT_DEBUG4(msg,param1,param2,param3) FX_OUTPUT_LOG_FUNC(msg,param1,param2,param3)
	#endif
	#ifndef FOXIT_DEBUG5
		#define FOXIT_DEBUG5(msg,param1,param2,param3,param4) FX_OUTPUT_LOG_FUNC(msg,param1,param2,param3,param4)
	#endif
	#ifndef FOXIT_DEBUG6
		#define FOXIT_DEBUG6(msg,param1,param2,param3,param4,param5) FX_OUTPUT_LOG_FUNC(msg,param1,param2,param3,param4,param5)
	#endif
	#ifndef FOXIT_DEBUG7
		#define FOXIT_DEBUG7(msg,param1,param2,param3,param4,param5,param6) FX_OUTPUT_LOG_FUNC(msg,param1,param2,param3,param4,param5,param6)
	#endif
	#ifndef FOXIT_DEBUG8
		#define FOXIT_DEBUG8(msg,param1,param2,param3,param4,param5,param6,param7) FX_OUTPUT_LOG_FUNC(msg,param1,param2,param3,param4,param5,param6,param7)
	#endif
	#ifndef FOXIT_DEBUG9
		#define FOXIT_DEBUG9(msg,param1,param2,param3,param4,param5,param6,param7,param8) FX_OUTPUT_LOG_FUNC(msg,param1,param2,param3,param4,param5,param6,param7,param8)
	#endif
	#ifndef FOXIT_DEBUG10
		#define FOXIT_DEBUG10(msg,param1,param2,param3,param4,param5,param6,param7,param8,param9) FX_OUTPUT_LOG_FUNC(msg,param1,param2,param3,param4,param5,param6,param7,param8,param9)
	#endif
#else
	#ifndef FOXIT_DEBUG1
		#define FOXIT_DEBUG1(msg)
	#endif
	#ifndef FOXIT_DEBUG2
		#define FOXIT_DEBUG2(msg,param1)
	#endif
	#ifndef FOXIT_DEBUG3
		#define FOXIT_DEBUG3(msg,param1,param2)
	#endif
	#ifndef FOXIT_DEBUG4
		#define FOXIT_DEBUG4(msg,param1,param2,param3)
	#endif
	#ifndef FOXIT_DEBUG5
		#define FOXIT_DEBUG5(msg,param1,param2,param3,param4)
	#endif
	#ifndef FOXIT_DEBUG6
		#define FOXIT_DEBUG6(msg,param1,param2,param3,param4,param5)
	#endif
	#ifndef FOXIT_DEBUG7
		#define FOXIT_DEBUG7(msg,param1,param2,param3,param4,param5,param6)
	#endif
	#ifndef FOXIT_DEBUG8
		#define FOXIT_DEBUG8(msg,param1,param2,param3,param4,param5,param6,param7)
	#endif
	#ifndef FOXIT_DEBUG9
		#define FOXIT_DEBUG9(msg,param1,param2,param3,param4,param5,param6,param7,param8)
	#endif
	#ifndef FOXIT_DEBUG10
		#define FOXIT_DEBUG10(msg,param1,param2,param3,param4,param5,param6,param7,param8,param9)
	#endif
#endif

#ifndef _FXM_OPENSOURCE_

//*****************************************************************************
//* Testing parameters
//*****************************************************************************
/**
 * @name Definition for testing parameters
 */
/*@{*/

typedef struct _FX_TESTPARAMS
{
	/** Size of the current parameter structure, for expansion purpose. */
	size_t			size;
	/** Project ID. */
	FX_DWORD		projectID;
	/** Version number. */
	FX_DWORD		version;
	/** Module ID. */
	FX_DWORD		moduleID;
	/** Feature ID. */
	FX_DWORD		featureID;
	/** Error code. */
	FX_INT32		errCode;
}FX_TESTPARAMS;

/** Initialize base testing parameters. This function doesn't set size field, please set its value separately. */
void FX_TestParams_Init(FX_TESTPARAMS *testParams, FX_DWORD projectID, FX_DWORD version, FX_DWORD moduleID, FX_DWORD featureID);

class CPDF_Parser;
class CPDF_Document;
typedef struct _FX_TESTPARAMS_PDFDOC
{
	/** base parameters, should be the first item in parameter structure. */
	FX_TESTPARAMS		base;

	/** PDF parser object. */
	CPDF_Parser*		pdfParser;
	/** PDF document object. */
	CPDF_Document*		pdfDocument;
}FX_TESTPARAMS_PDFDOC;

/** Initialize PDF Document testing parameters. This function doesn't set size field, please set its value separately. */
void FX_TestParams_PDFDoc_Init(FX_TESTPARAMS_PDFDOC *pdfDocParams, CPDF_Parser *pdfParser, CPDF_Document *pdfDoc);

/*@}*/

//*****************************************************************************
//* Testing functions
//*****************************************************************************
/**
 * @name Interface for testing functions
 */
/*@{*/

/**
 * @brief	Callback function type for a testing function.
 *
 * @param[in] testParams	testing parameters.
 * @param[in] userParams	user parameters;
 */
typedef void (*FX_LPFTestProc)(FX_TESTPARAMS *testParams, FX_TESTPARAMS *userParams);

typedef void * FX_HTEST;

/**
 * @brief	Get the count of all children for a testing function.
 *
 * @param[in] hTest		A test procedure handle.
 * @param[in] parent	parent testing function.
 *
 * @return	Total count of all children for a given parent. If parent is NULL, returns all root items.
 */
FX_INT32	FX_TestProc_CountChildren(FX_HTEST hTest, FX_LPFTestProc parent);
/**
 * @brief	Get a child of testing function.
 *
 * @param[in] hTest	 A test procedure handle.
 * @param[in] parent	parent testing function.
 * @param[in] index		index of child.
 *
 * @return	Child function pointer, or NULL if fails.
 */
FX_LPFTestProc	FX_TestProc_GetChild(FX_HTEST hTest, FX_LPFTestProc parent, FX_INT32 index);

/**
 * @brief	Get ID of testing function.
 *
 * @param[in] hTest	 A test procedure handle.
 * @param[in] testProc	testing function.
 *
 * @return	ID of testing function.
 */
FX_DWORD	FX_TestProc_GetID(FX_HTEST hTest, FX_LPFTestProc testProc);

/**
 * @brief	Get description string of testing function.
 *
 * @param[in] hTest	 A test procedure handle.
 * @param[in] testProc	testing function.
 *
 * @return	Description string of testing function.
 */
FX_LPCWSTR	FX_TestProc_GetDescription(FX_HTEST hTest, FX_LPFTestProc testProc);

/**
 * @brief	Callback function type for a main entry of testing codes.
 *
 * @param[in] argc	Count of arguments in main entry.
 * @param[in] argv	List of arguments in main entry.
 *
 * @return	Any code to indicate running state.
 */
typedef FX_INT32 (*FX_LPFTestMain)(FX_INT32 argc, FX_CHAR **argv);

/**
 * @brief	Load configuration data of testing functions from an XML stream.
 *
 * @param[in] pFile		Reading file stream object.
 *
 * @return	A test procedure handle.
 */
FX_HTEST FX_TestProc_LoadFromXML(IFX_FileRead *pFile);

typedef struct _FX_TESTPROC
{
	/** ID of testing function.*/
	FX_DWORD		dwProcID;
	
	/** Testing function. */
	FX_LPFTestProc	pTestProc;

} FX_TESTPROC;

/**
 * @brief	Initialize the test procedure array.
 *
 * @param[in] hTest		A test procedure handle.
 * @param[in] pArray	The pointer of test procedure array.
 * @param[in] size		The array size.
 *
 */
void FX_TestProc_InitArray(FX_HTEST hTest, FX_TESTPROC* pArray, size_t size);

/**
 * @brief	Save configuration data of testing functions into an XML stream.
 *
 * @param[in] hTest	 A test procedure handle.
 * @param[in] pFile		Writing file stream object.
 *
 * @return	TRUE if write successfully, FALSE if failure.
 */
FX_BOOL		FX_TestProc_SaveToXML(FX_HTEST hTest, IFX_FileWrite *pFile);

/**
 * @brief	Release a test procedure handle.
 *
 * @param[in] hTest	 A test procedure handle, which should be created by FX_TestProc_LoadFromXML.
 */
void		FX_TestProc_Release(FX_HTEST hTest);

/*@}*/

//*****************************************************************************
//* Console Debugging functions
//*****************************************************************************
/**
 * @name Interface for debugging support
 */
/*@{*/

/** Callback structure for debugging device. */
typedef struct _FX_DEBUGDEVICE
{
	/** Internal data pointer, maintained by implementor. */
	FX_LPVOID	m_pUserData;

	/**
	 * @brief	Initialize device.
	 *
	 * @param[in] debugDevice	debugging device object used currently.
	 *
	 * @return	TRUE if initialize successfully, or FALSE for failure.
	 */
	FX_BOOL		(*Initialize)(struct _FX_DEBUGDEVICE *debugDevice);
	/**
	 * @brief	Finalize device and destroy the current object.
	 *
	 * @param[in] debugDevice	debugging device object used currently.
	 */
	void		(*Finalize)(struct _FX_DEBUGDEVICE *debugDevice);

	/**
	 * @brief	Output a byte string into debugging device.
	 *
	 * @param[in] debugDevice	debugging device object used currently.
	 * @param[in] str			byte string, should contain a NULL terminator.
	 */
	void		(*OutputStringA)(struct _FX_DEBUGDEVICE *debugDevice, FX_LPCSTR str);
	/**
	 * @brief	Output a wide string into debugging device.
	 *
	 * @param[in] debugDevice	debugging device object used currently.
	 * @param[in] str			wide string, should contain a NULL terminator.
	 */
	void		(*OutputStringW)(struct _FX_DEBUGDEVICE *debugDevice, FX_LPCWSTR str);
	/**
	 * @brief	Output a binary buffer into debugging device.
	 *
	 * @param[in] debugDevice	debugging device object used currently.
	 * @param[in] buffer		binary buffer.
	 * @param[in] size			size of binary buffer, in bytes.
	 */
	void		(*OutputBinary)(struct _FX_DEBUGDEVICE *debugDevice, FX_LPCBYTE buffer, size_t size);
}FX_DEBUGDEVICE, *FX_HDEBUG;

/**
 * @brief	Create a debugging device based upon stdout device.
 *
 * @return	Debugging device object.
 */
#ifdef _FX_DEBUG_
	FX_HDEBUG	FX_Debug_CreateStdout();
#else
	#define		FX_Debug_CreateStdout()		NULL
#endif
/**
 * @brief	Create a debugging device based upon Command Line or Shell environment.
 *
 * @return	Debugging device object.
 */
#ifdef _FX_DEBUG_
	FX_HDEBUG	FX_Debug_CreateCmdLine();
#else
	#define		FX_Debug_CreateCmdLine()	NULL
#endif
/**
 * @brief	Create a console-based debugging device.
 *
 * @return	Debugging device object.
 */
#ifdef _FX_DEBUG_
	FX_HDEBUG	FX_Debug_CreateConsole();
#else
	#define		FX_Debug_CreateConsole()	NULL
#endif
/**
 * @brief	Create a debugging device based upon a writing stream.
 *
 * param[in] pSW	a writing stream object to receive debugging data.
 *
 * @return	Debugging device object.
 */
#ifdef _FX_DEBUG_
	FX_HDEBUG	FX_Debug_CreateStream(IFX_StreamWrite *pSW);
#else
	#define		FX_Debug_CreateStream(pSW)	NULL
#endif
/**
 * @brief	Release a debugging device object.
 *
 * @param[in] hDebug	debugging device object, which should be created by FX_Debug_CreateStdout,
 *						FX_Debug_CreateCmdLine, FX_Debug_CreateConsole, or FX_Debug_CreateStream.
 */
#ifdef _FX_DEBUG_
	void		FX_Debug_Release(FX_HDEBUG hDebug);
#else
	#define		FX_Debug_Release(hDebug)
#endif

/**
 * @brief	Retrieve the current default debugging device.
 *
 * @return	default debugging device object.
 */
#ifdef _FX_DEBUG_
	FX_HDEBUG	FX_Debug_GetDefault();
#else
	#define		FX_Debug_GetDefault()	NULL
#endif
/**
 * @brief	Set a default debugging device.
 */
#ifdef _FX_DEBUG_
	void		FX_Debug_SetDefault(FX_HDEBUG hDebug);
#else
	#define		FX_Debug_SetDefault(hDebug)
#endif

/**
 * @brief	Output debugging information as a byte string.
 *
 * @param[in] fmtStr	format string.
 */
#ifdef _FX_DEBUG_
	void		FX_Debug_OutputStringA(FX_LPCSTR fmtStr, ...);
#else
	#if (_FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN32_MOBILE_ || _FX_OS_ == _FX_WIN64_)
		#define		FX_Debug_OutputStringA()
	#else
		#define		FX_Debug_OutputStringA(...)
	#endif
#endif
/**
 * @brief	Output debugging information as a wide string.
 *
 * @param[in] fmtStr	format string.
 */
#ifdef _FX_DEBUG_
	void		FX_Debug_OutputStringW(FX_LPCWSTR fmtStr, ...);
#else
	#if (_FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN32_MOBILE_ || _FX_OS_ == _FX_WIN64_)
		#define		FX_Debug_OutputStringW()
	#else
		#define		FX_Debug_OutputStringW(...)
	#endif
#endif
/**
 * @brief	Output binary data.
 *
 * @param[in] buffer	buffer of binary data.
 * @param[in] size		size of binary data, in bytes.
 */
#ifdef _FX_DEBUG_
	void		FX_Debug_OutputBinary(FX_LPCBYTE buffer, size_t size);
#else
	#define		FX_Debug_OutputBinary(buffer, size)
#endif

/*@}*/

#endif //_FXM_OPENSOURCE_

#ifdef __cplusplus
}
#endif

#endif //_FXCRT_DEBUG_

#endif //_FXM_OPENSOURCE_

/** @} */
